package com.dc.java8._1_lambda;

import org.junit.Test;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * 使用Lambdas和Streams
 *	Stream是对集合的包装,通常和lambda一起使用。 
 *	使用lambdas可以支持许多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等。
 *  同样,Stream使用懒运算,他们并不会真正地读取所有数据,遇到像getFirst() 这样的方法就会结束链式语法
 *	
 *	学习资料：https://www.cnblogs.com/franson-2016/p/5593080.html
 */
public class LambdaTest3 {

	List<Person> persons = Arrays.asList(
			new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000.0),
			new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500.0),
			new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800.0),
			new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600.0),
			new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200.0),
			new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900.0),
			new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300.0),
			new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700.0),
			new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000.0),
			new Person("Addison", "Pam", "Java programmer", "female", 34, 1300.0)
			);

	@Test
	public void test1(){
		System.out.println("所有人的名称：");
		persons.forEach(p -> System.out.printf("%s %s %n", p.getFirstName(),p.getLastName()));

		System.out.println("\n\n----------------------分割线------------------------");

		System.out.println("显示所有员工的工资：");
		persons.forEach(p -> System.out.printf("%s %s的工资是：%10.2f %n", p.getFirstName(),p.getLastName(),p.getSalary()));
	}

	@Test
	public void test2(){

		/**
		 * Consumer 接口
		 * 		表示一个接受单个输入参数并且没有返回值的操作。
		 * 		不像其它函数式接口，Consumer接口期望执行带有副作用的操作(Consumer的操作可能会更改输入参数的内部状态)
		 */
		Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() * 1.1);
		
		// 此处需要把修改后的 Consumer 重新放入到 之前的列表中
		persons.forEach(giveRaise);	
		
		persons.forEach(p -> System.out.printf("%s 提升后的工资是：%10.2f %n", p.getLastName(), p.getSalary()) );
	}

	/**
	 * 过滤出工资超过 2000 的员工，然后进行遍历
	 */
	@Test
	public void test3(){
		System.out.println("\n\n---------------------显示工资超过2000的员工及工资----------------------");
		persons.stream()
				.filter(p -> p.getSalary() > 2000)
				.forEach(p -> System.out.printf("%s %s的工资是：%10.2f %n", p.getFirstName(), p.getLastName(), p.getSalary()) );
	}

	/**
	 * 定义过滤器,可以根据情况，重用
	 */
	@Test
	public void test4(){
		Predicate<Person> ageFilter = p -> p.getAge() > 30;
		Predicate<Person> salFilter = p -> p.getSalary() > 2000;

		System.out.println("\n\n---------下面是年龄大于 30 ，工资超过 2000的员工-----------");
		persons.stream().filter(ageFilter)
				.filter(salFilter)
				.forEach(p -> System.out.printf("%s 的年龄为%d,工资是：%10.2f", p.getLastName(),p.getAge(),p.getSalary()) );

	}

	/**
	 * 通过使用limit方法，限制结果的个数
	 */
	@Test
	public void test5(){
		System.out.println("\n\n------------------获取前三个结果----------------------");
		persons.stream()
				.limit(3)
				.forEach(p -> System.out.println(p.getLastName()));
	}

	/**
	 * 根据排序，并显示前5个
	 */
	@Test
	public void test6(){
		System.out.println("\n\n--------------根据名称排序，并显示前5个-----------------");
		persons.stream()
				.sorted(Comparator.comparing(Person::getLastName))
				.limit(5)
				.forEach(p -> System.out.println(p.getLastName()));

		System.out.println("\n\n--------------根据年龄排序，并显示前5个-----------------");
		persons.stream()
				.sorted(Comparator.comparingInt(Person::getAge))
				.limit(5)
				.forEach(p -> System.out.println(p.getAge()) );
	}

	/**
	 * 获取最大、最小数据
	 */
	@Test
	public void test7(){
		System.out.println("\n\n----------------显示薪水最高和最低的员工信息-------------------");
		Person person1 = persons.stream()
				.min(Comparator.comparing(Person::getSalary))
				.get();
		System.out.println("最低工资为：" + person1.getSalary());

		Person person2 = persons.stream()
				.max(Comparator.comparing(Person::getSalary))
				.get();
		System.out.println("最高的工资为：" + person2.getSalary());
	}

	/**
	 * 数据拼装为字符串
	 */
	@Test
	public void test8(){
		System.out.println("\n\n----------------将firstName 拼接成一个字符串-----------------------");
		String collect = persons.stream()
				.map(Person::getFirstName)
				.collect(Collectors.joining(";"));
		System.out.println("拼接的字符串为：" + collect);
	}

	/**
	 * 数据 存放到 Set 和 TreeSet 中
	 */
	@Test
	public void test9(){
		System.out.println("\n\n----------------将firstName 存放到Set 中-----------------------");
		Set<String> pSet = persons.stream()
				.map(Person::getFirstName)
				.collect(Collectors.toSet());
		pSet.forEach(System.out::println);

		System.out.println("\n\n----------------将firstName 存放到TreeSet 中-----------------------");
		TreeSet<String> treeSet = persons.stream()
				.map(Person::getFirstName)
				.collect(Collectors.toCollection(TreeSet::new));
		treeSet.forEach(System.out::println);
	}

	/**
	 * 数据求和
	 */
	@Test
	public void test10(){
		System.out.println("\n\n---------------工资求和-------------------------");
		double sumSal = persons.parallelStream()
				.mapToDouble(Person::getSalary)
				.sum();
		System.out.println("所有员工的总工资为" + sumSal);
	}

	/**
	 * 获取 summaryStatistics 类型的数据对象
	 */
	@Test
	public void test11(){
		System.out.println("\n\n----------------------使用summaryStatistics方法获得stream 中元素的各种汇总数据--------------------");
		List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		IntSummaryStatistics stats = numbers.stream()
				.mapToInt((x) -> x )
				.summaryStatistics();

		System.out.println("list 中的最大数字为：" + stats.getMax());
		System.out.println("list 中的最小数字为：" + stats.getMin());
		System.out.println("list 中的数字之和为：" + stats.getSum());
		System.out.println("list 中的数字的平均值为：" + stats.getAverage());
	}

}
